using System.Text;
using DE.Sdc.Tools.Replacer;
using Ionic.Crc;
using Ionic.Zip;
using Microsoft.SharePoint;
using System.Security.Principal;
using System.IO;
using System.Web;
using System.Diagnostics;
using System.Collections.Generic;
using System.Text.RegularExpressions;
using System.Globalization;
using System.Xml;
using System.Resources;
using System;
using System.Threading;
using Microsoft.SharePoint.Utilities;
//using DE.Sdc.SharePoint.Foundation.HelperUtilities;

namespace DE.Sdc.SharePoint.SPContentStructure.Import
{
    public static class DeploymentHelper
    {

        private const String FileExtensions = "txt;xml;webpart;dwp;aspx;ascx;bat;cmd;js;master;vb;vba";

        /// <summary>
        /// Gets the web in a parent web or site
        /// </summary>
        /// <param name="parent">The parent web or site</param>
        /// <returns>The </returns>
        internal static SPWeb GetWeb(object parent)
        {
            if (parent is SPSite)
                return ((SPSite)parent).RootWeb;

            return (SPWeb)parent;
        }

        /// <summary>
        /// Creates a new http context from a given context url and sets the HttpContext.Current
        /// </summary>
        /// <param name="contextUrl">Absolute http url which context should used</param>
        public static void CreateContext(string contextUrl)
        {
            Trace.WriteLine("Try to create context.", "ContentStructureImporter:CreateContext");

            if (SPContentStructureImport.CurrentContextInitiallySet)
                return;

            HttpRequest request = new HttpRequest(Path.GetFileName(contextUrl), contextUrl, null)
                                      {Browser = new HttpBrowserCapabilities()};

            //var wrapper = new HttpBrowserCapabilitiesWrapper(new HttpBrowserCapabilities());

            HttpResponse response = new HttpResponse(new StringWriter());

            HttpContext context = new HttpContext(request, response);

            WindowsIdentity currentIdentity = WindowsIdentity.GetCurrent();

            if (currentIdentity != null)
                context.User = new WindowsPrincipal(currentIdentity);

            HttpContext.Current = context;

            //if (_currentContextProperty == null)
            //    _currentContextProperty = typeof(HttpContext).GetProperty("Current",
            //                                                     BindingFlags.Public | BindingFlags.Static |
            //                                                     BindingFlags.SetProperty);
            //_currentContextProperty.SetValue(null, context, null);

            Trace.WriteLine("Context created.", "ContentStructureImporter:CreateContext");
        }

        /// <summary>
        /// Deletes the current http context
        /// </summary>
        public static void ClearContext()
        {
            Trace.WriteLine("Try to clear context.", "ContentStructureImporter:ClearContext");


            if (SPContentStructureImport.CurrentContextInitiallySet)
                return;

            HttpContext.Current = null;
            //if (_currentContextProperty == null)
            //    _currentContextProperty = typeof(HttpContext).GetProperty("Current",
            //                                                     BindingFlags.Public | BindingFlags.Static |
            //                                                     BindingFlags.SetProperty);
            //_currentContextProperty.SetValue(null, null, null);

            Trace.WriteLine("Context cleared.", "ContentStructureImporter:ClearContext");
        }

        /// <summary>
        /// Replaces the namespace in a given input string
        /// </summary>
        /// <param name="input">A string where the namespace should replaced</param>
        /// <param name="namespaceUri">A string with the namespace value</param>
        /// <returns>The cleaned up string</returns>
        internal static string RemoveNamespace(string input, string namespaceUri)
        {
            return input.Replace("xmlns=\"" + namespaceUri + "\"", "");
        }

        internal static byte[] ReadFile(String filePath, System.Text.Encoding encoding)
        {
            var contentStructureZipPath = DeploymentContext.Current.GetContentStructureZipPath();
            if (!System.IO.File.Exists(contentStructureZipPath))
                return ReadFileNoneZip(filePath, encoding);            
 
            using (MemoryStream mem = new MemoryStream())
            {
                using (ZipFile zip = ZipFile.Read(contentStructureZipPath))
                {
                    zip.FlattenFoldersOnExtract = true;
                    ZipEntry e = zip[ConvertToUTF8(filePath)];
                    e.Extract(mem);
                    return mem.ToArray();
                    #warning Not Testted File import encoding 
                }
            }

            
    
        }

        internal static string ConvertToUTF8(string input)
        {
            var isoEncoding = Encoding.GetEncoding("ISO-8859-1");
            var utf8Encoding = Encoding.UTF8;

            var utfBytes = utf8Encoding.GetBytes(input);
            var isoBytes = Encoding.Convert(utf8Encoding, isoEncoding, utfBytes);

            return (isoEncoding.GetString(isoBytes));
        }

        internal static byte[] ReadFileNoneZip(String filePath, System.Text.Encoding encoding)
        {
            String extension = filePath.Substring(filePath.LastIndexOf(".") + 1);

            if (FileExtensions.IndexOf(extension.ToLowerInvariant(), StringComparison.Ordinal) != -1)
            {
                String fileContent = System.IO.File.ReadAllText(filePath, System.Text.Encoding.UTF8);
                return encoding.GetBytes(Resolve(fileContent));
                
            }
            return System.IO.File.ReadAllBytes(filePath);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="url"></param>
        /// <param name="parentUrl"></param>
        /// <returns></returns>
        public static string GetRootedUrl(string url, string parentUrl)
        {
            if (!string.IsNullOrEmpty(url))
            {
                if (url.StartsWith("/") || url.StartsWith("http") || url.StartsWith(@"\\") || url.StartsWith("#") || url.StartsWith("javascript:"))
                    return url;

                return parentUrl.TrimEnd('/') + "/" + url;
            }

            return null;
        }

        public static string Resolve(string input)
        {
            return Resolve(input, null);
        }

        public static string Resolve(string input, CultureInfo culture)
        {
            if (string.IsNullOrEmpty(input))
                return input;

            
            string resolvedInput = input;
            
            if (culture != null)
            {
                Thread.CurrentThread.CurrentUICulture = culture;
                Regex regex = new Regex(@"\$.*?\;", RegexOptions.Multiline);
                resolvedInput = regex.Replace(resolvedInput, new MatchEvaluator(ResolveResource));
            }

            return resolvedInput;    
        }

        private static string ResolveResource(Match match)
        {
            try
            {
                Regex regex = new Regex(@"(?<=\$Resources:).*?(?=\;)", RegexOptions.Multiline | RegexOptions.IgnoreCase);
                // $Resource:ClassKey,ResourceKey; --> excludes $Resources; leaves ClassKey,ResourceKey
                Match resourceMatch = regex.Match(match.Value);
                var resourceFields = System.Web.Compilation.ResourceExpressionBuilder.ParseExpression(resourceMatch.Value);
                string resourceValue = null;
                string resourceDir = SPUtility.GetGenericSetupPath("Resources");

                if (resourceFields != null)
                {
                    try
                    {
                        resourceValue =
                            HttpContext.GetGlobalResourceObject(resourceFields.ClassKey, resourceFields.ResourceKey,
                                                                Thread.CurrentThread.CurrentUICulture) as string;
                    }
                    catch
                    {
                    }

                    if (resourceValue == null)
                    {
                        
                        try
                        {
                            ResourceManager resourceManager = new ResxResourceManager(resourceFields.ClassKey,
                                                                                      resourceDir);
                            //ResourceManager.CreateFileBasedResourceManager(resourceFields.ClassKey, resourceDir,
                            //                                               null);
                            resourceValue = resourceManager.GetString(resourceFields.ResourceKey);
                        }
                        catch
                        {
                        }
                    }

                    if (resourceValue == null)
                    {
                        string resourceFile = Path.Combine(resourceDir,
                                                                     resourceFields.ClassKey + "." +
                                                                     Thread.CurrentThread.CurrentUICulture.Name +
                                                                     ".resx");

                        if (!System.IO.File.Exists(resourceFile))
                        {
                            resourceFile = Path.Combine(resourceDir,
                                                                  resourceFields.ClassKey + ".resx");
                        }

                        XmlDocument resourceDocument = new XmlDocument();
                        resourceDocument.Load(resourceFile);

                        if (resourceDocument.DocumentElement != null)
                        {
                            XmlNode resourceNode =
                                resourceDocument.DocumentElement.SelectSingleNode("//Data/Value [../@Name='" +
                                                                                  resourceFields.ResourceKey +
                                                                                  "'] | //data/value [../@name='" +
                                                                                  resourceFields.ResourceKey +
                                                                                  "']");

                            resourceValue = resourceNode.InnerText;
                        }
                    }
                }

                if (string.IsNullOrEmpty(resourceValue) && resourceFields != null && resourceFields.ResourceKey == "Culture")
                    resourceValue = Thread.CurrentThread.CurrentUICulture.Name;

                return resourceValue;
            }
            catch (Exception ex)
            {
                throw new ArgumentException("Error while reading the resource " + match.Value, ex);
            }
        }

        

        #region FromHelpers
        

        public static void RemoveGroupFromWeb(SPWeb web, String groupname)
        {
            if (CheckIfGroupExistsOnWeb(web, groupname))
            {
                web.AllowUnsafeUpdates = true;
                web.SiteGroups.Remove(groupname);
                web.Update();
                //web.AllowUnsafeUpdates = false;
            }
        }

        public static bool CheckIfGroupExistsOnWeb(SPWeb web, String groupName)
        {
            for (int i = 0; i < web.SiteGroups.Count; i++)
            {
                if (web.SiteGroups[i].Name.Equals(groupName))
                    return true;
            }
            Trace.WriteLine(string.Format("Gruppe {0} ist im Web {1} nicht vorhanden.", groupName, web.Url));
            return false;
        }

        public static void SetEnforceUniqueValues(SPList list, string fieldInternalName)
        {
            SetEnforceUniqueValues(list, list.Fields.GetFieldByInternalName(fieldInternalName).Id);
        }
        public static void SetEnforceUniqueValues(SPList list, Guid fieldId)
        {
            var field = list.Fields[fieldId];
            field.Indexed = true;
            //field. = true;
            field.Update();
        }



        #endregion

        #region NewHelpers
        public static string GetFieldValueUserLogin(this SPListItem item,
  string fieldName)
        {
            if (item != null)
            {
                SPFieldUserValue userValue =
                  new SPFieldUserValue(
                    item.Web, item[fieldName] as string);
                return userValue.User.LoginName;
            }
            else
            {
                return string.Empty;
            }
        }

        /// <summary>
        /// Sets the value of a User-Field to a login name.
        /// </summary>
        public static void SetFieldValueUser(this SPListItem item,
          string fieldName, string loginName)
        {
            if (item != null)
            {
                item[fieldName] = item.Web.EnsureUser(loginName);
            }
        }

        /// <summary>
        /// Sets the value of a User-Field to an SPPrincipal 
        /// (SPGroup or SPUser).
        /// </summary>
        public static void SetFieldValueUser(this SPListItem item,
          string fieldName, SPPrincipal principal)
        {
            if (item != null)
            {
                item[fieldName] = principal;
            }
        }

        public static void SetFieldValueUser(this SPListItem item,
          string fieldName, IEnumerable<SPPrincipal> principals)
        {
            if (item != null)
            {
                SPFieldUserValueCollection fieldValues =
                  new SPFieldUserValueCollection();

                foreach (SPPrincipal principal in principals)
                {
                    fieldValues.Add(
                      new SPFieldUserValue(
                        item.Web, principal.ID, principal.Name));
                }
                item[fieldName] = fieldValues;
            }
        }

        /// <summary>
        /// Sets the value of a multivalue User-Field to 
        /// a list of user names.
        /// </summary>
        public static void SetFieldValueUser(this SPListItem item,
          string fieldName, IEnumerable<string> loginNames)
        {
            if (item != null)
            {
                SPFieldUserValueCollection fieldValues =
                  new SPFieldUserValueCollection();

                foreach (string loginName in loginNames)
                {
                    SPUser user = item.Web.EnsureUser(loginName);
                    fieldValues.Add(
                      new SPFieldUserValue(
                        item.Web, user.ID, user.Name));
                }

                item[fieldName] = fieldValues;
            }
        }
#endregion
    }
}
